#include <stack>
#include "GeneralVisitor.h"
#include "ExecutionResult.h"

class InterpreterVisitor: public GeneralVisitor
{
public:
    InterpreterVisitor(FunctionDefinition* iEntryPoint);
    ~InterpreterVisitor();

    void Run();

    virtual void Visit(ArrayAccess* iNode);
    virtual void Visit(BinaryOperation* iNode);
    virtual void Visit(ConstantValue* iNode);
    virtual void Visit(FieldAccess* iNode);
    virtual void Visit(UnaryOperation* iNode);
    virtual void Visit(Variable* iNode);
    virtual void Visit(Assign* iNode);
    virtual void Visit(EmptyStatement* iNode);
    virtual void Visit(ForLoop* iNode);
    virtual void Visit(IfStatement* iNode);
    virtual void Visit(NewExpression* iNode);
    virtual void Visit(ReturnStatement* iNode);
    virtual void Visit(StatementList* iNode);
    virtual void Visit(VarDeclaration* iNode);
    virtual void Visit(WhileLoop* iNode);
    virtual void Visit(FunctionCall* iNode);
    virtual void Visit(MethodCall* iNode);
    virtual void Visit(ClassDefinition* iNode);
    virtual void Visit(FunctionDefinition* iNode);
    virtual void Visit(MethodDefinition* iNode);

private:
    FunctionDefinition* fEntryPoint; // toto v destruktoru nemazat - o to se postara ParseHelper

    // Tady jsou lokální proměnné. Při zavolání funkce nebo metody se na zásobník vloží další vrstva, kam se na začátku
    // nastaví hodnoty funkčních parametrů (ty se taky chovají jako lokální proměnné).
    // Tímto způsobem je elegantně vyřešený scope proměnných.
    stack<map<string, ExpressionValue*> > fLocalVars;

    // Sem se ukládají výsledky provádění příkazů. V podstatě by měla stačit jediná hodnota, ale člověk nikdy neví.
    stack<ExecutionResult*> fExecutionResults;

    // Tohle je halda. Sem se ukládají odkazy na ExpressionValue, které jsou instancemi objektů nebo polí.
    // Takové hodnoty musí být odkazovány ještě z jiného místa než ze zásobníku lokálních proměnných, protože
    // v případě vzniku kruhových referencí, kdy původní lokální proměnné začnou odkazovat na něco jiného
    // a na kruh již nic neukazuje, bychom to sami neuměli nijak vymazat!
    vector<ExpressionValue*> fHeap;

    // Tohle je stack pro vyrazy - sem se davaji napr. vyhodnocene leve a prave podvyrazy binarnich operaci a podobne.
    // Poradi vkladani na zasobnik musi byt takove, aby odebirani bylo intuitivni - tj. pro binarni operace bude na vrcholu
    // leva hodnota a pod ni prava a podobne.
    stack<ExpressionValue*> fExpressionStack;

    // Zasobnik seznamu hodnot. Tohle se pouziva pro volani funkci a metod - volajici na zasobnik vzdy da seznam vyhodnocenych
    // parametru. Tohle je cistsi a bezpecnejsi zpusob nez pres fExpressionStack - co kdyz nekdo zavola funkci s chybnym
    // poctem parametru? Takhle to zjistim jednoduse z velikosti vektoru ;-)
    stack<vector<ExpressionValue*> > fCallParamsStack;

    void ReferenceValue(ExpressionValue* oValue)                { oValue->Reference(); }
    void DereferenceValue(ExpressionValue* oValue);
    void SetLocalVar(string iVarName, ExpressionValue* iValue);
};
